package com.fudan.es.entity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.elasticsearch.search.aggregations.AggregationBuilder;

import com.fudan.es.Aggs;
import com.fudan.es.aggs.entity.MetricDef;
import com.fudan.es.aggs.handler.base.AggsHandler;

public class MetricPack extends Pack{
	private String name;
	private MetricType type;

	private FieldMeta grain;

	private FieldMeta field;
	private List<MetricPack> metric;

	private Integer size = 10;
	private String missing;
	private String other;
	private String interval = "1M";
	public static MetricPack build(FieldMeta field,MetricType type,MetricDef metricDef) {
		MetricPack metricPack = new MetricPack();
		metricPack.field = field;
		metricPack.type = type;
		if(metricDef.getSize() != null) {
			metricPack.size = metricDef.getSize();
		}
		//AggregationBuilder aggs = MetricHandler.buildHandler(type).handle(null,metricPack);
		//metricPack.root = MetricHandler.buildHandler(type).build(metricPack);
		return metricPack;
	}

	public void generateAggregation() {
		//this.root = MetricHandler.buildHandler(type).build(this);
		this.root = AggsHandler.buildHandler(type).build(this);
	}

	private void subMetric(MetricPack subMetric) {
		if(metric == null) {
			metric = new ArrayList<MetricPack>();
		}
		metric.add(subMetric);
		//需要判断与root的关系
		//如果子聚合与root属于同一级直接在root后加子节点
		//如果子聚合是root的下一级，则在root后直接加下一层的path
		//如果子聚合是root的上级，但在同一颗子树下，则要在root的reverse节点中加入对应节点
		//如果子聚合是root的上级，且不在同一颗子树下，则要在root的rootReverse节点后再加入该层的path
	}

	public void add(MetricPack subMetric) {
		FieldMeta subField = subMetric.getField();
		if(subField.getInNested()) {
			if(field.getInNested()) {
				if(field.getNestedPath().equals(subField.getNestedPath())) {
					root.subAggregation(subMetric.getRoot());
				}else if(field.getNestedPath().contains(subField.getNestedPath())) {
					//root->sub (reverse:sub_path)
					AggregationBuilder aggs = getreverseByPath(subField.getNestedPath()).subAggregation(subMetric.getRoot());
					//root.subAggregation(aggs);
				}else if(subField.getNestedPath().contains(field.getNestedPath())) {
					//sub->root (nested:sub_path)
					AggregationBuilder aggs = getNestedByPath(subField.getNestedPath()).subAggregation(subMetric.getRoot());
					//root.subAggregation(aggs);
				}else {
					//root->reverse->nested(reverse:root->nested:sub_path)
					Collection<AggregationBuilder> subAggs = getreverseByPath(null).getSubAggregations();
					boolean fill = true;
					for (AggregationBuilder aggregationBuilder : subAggs) {
						if(aggregationBuilder.getName().equals(subField.getNestedPath()) && aggregationBuilder.getType().equals("nested")) {
							aggregationBuilder.subAggregation(subMetric.getRoot());
							fill = false;
						}
					}
					if(fill) {
						AggregationBuilder aggs = getreverseByPath(null).subAggregation(Aggs.nested(subField.getNestedPath(), subField.getNestedPath()).subAggregation(subMetric.getRoot()));
					}
					//root.subAggregation(aggs);
				}
			}
			else {
				//root:no,sub:nested
				AggregationBuilder aggs = getNestedByPath(subField.getNestedPath()).subAggregation(subMetric.getRoot());
				//root.subAggregation(aggs);
			}
		}else {
			if(field.getInNested()) {
				//root:nested,sub:no
				AggregationBuilder aggs = getreverseByPath(null).subAggregation(subMetric.getRoot());
				//root.subAggregation(aggs);
			}else {
				//root:no,sub:no
				root.subAggregation(subMetric.getRoot());
			}
		}
		subMetric(subMetric);
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public MetricType getType() {
		return type;
	}
	public void setType(MetricType type) {
		this.type = type;
	}
	public Integer getSize() {
		return size;
	}
	public void setSize(Integer size) {
		this.size = size;
	}

	public List<MetricPack> getMetric() {
		return metric;
	}

	public void setMetric(List<MetricPack> metric) {
		this.metric = metric;
	}

	public AggregationBuilder getRoot() {
		return root;
	}

	public void setRoot(AggregationBuilder root) {
		this.root = root;
	}

	public FieldMeta getField() {
		return field;
	}

	public void setField(FieldMeta field) {
		this.field = field;
	}

	public FieldMeta getGrain() {
		return grain;
	}

	public void setGrain(FieldMeta grain) {
		this.grain = grain;
	}


	public String getMissing() {
		return missing;
	}

	public void setMissing(String missing) {
		this.missing = missing;
	}

	public String getOther() {
		return other;
	}

	public void setOther(String other) {
		this.other = other;
	}
	public String getInterval() {
		return interval;
	}

	public void setInterval(String interval) {
		this.interval = interval;
	}


	public static enum MetricType {
		_COUNT,TERMS, SUM, AVG, DATE;

		@Override
		public String toString() {
			return super.toString().toLowerCase();
		}
	}

}
